package services

import (
	admindao "TaskAssignmentSystem/internal/admin/dao"
	"TaskAssignmentSystem/internal/app/dao"
	"TaskAssignmentSystem/internal/pkg/code"
	"TaskAssignmentSystem/internal/pkg/modelbase"
	"TaskAssignmentSystem/pkg/db/mysql"
	"TaskAssignmentSystem/pkg/db/redis"
	"TaskAssignmentSystem/pkg/oss"
	"TaskAssignmentSystem/pkg/timehandler"
	"TaskAssignmentSystem/pkg/utils"
	"errors"
	"fmt"
	"github.com/golang/glog"
	jsoniter "github.com/json-iterator/go"
	"gorm.io/gorm"
	"gorm.io/gorm/clause"
	"net/url"
	"regexp"
	"strings"
	"time"
)

type TopicService struct{}

func (t *TopicService) GetTopic(topicNumber int, projectId, topicId, topicName, labels, respondentId, teacherId, teamNumber string, tsTime, teTime, tdsTime, tdeTime int64, userId string, uid uint) (err error) {
	//检验领取题目数有没有超出用户的限制
	_db := mysql.GetDB()
	//检测当前用户有么有改项目的权限
	var user dao.SystemUserRestriction
	if err := _db.Model(&dao.SystemUserRestriction{}).Where(map[string]interface{}{"project_id": projectId, "system_user_id": uid}).First(&user).Error; err != nil {
		switch err {
		case gorm.ErrRecordNotFound:
			return errors.New("当前用户没有领取该项目的题目权限,请联系管理员")
		default:
			return err
		}
	}
	var project dao.SystemProject
	err = _db.Model(&dao.SystemProject{}).Where("project_id = ?", projectId).First(&project).Error
	if err != nil {
		return err
	}
	var topicServe CommonService[dao.SystemTopic]
	topicServe.WhereStr = []string{}
	topicServe.Query = map[string]interface{}{"project_id": project.ProjectId, "status": 5}
	//如果是一审项目,领取时则排除答主处理中的题目
	if project.EnumType == modelbase.AuditProj {
		topicServe.WhereStr = append(topicServe.WhereStr, fmt.Sprintf("topic_id in (select topic_id from tas_system_topic WHERE project_id = '%v' and `status` = 1 )", project.WorkProjectId))
	} else if project.EnumType == modelbase.FinalProj {
		//如果是二审项目,查询时排除一审处理中的题目和答主处理中的题目
		topicServe.WhereStr = append(topicServe.WhereStr, fmt.Sprintf("topic_id in (select topic_id from tas_system_topic WHERE project_id = '%v' and `status` = 1 and audit_status = 1 )", project.AuditProjectId))
		topicServe.WhereStr = append(topicServe.WhereStr, fmt.Sprintf("topic_id in (select topic_id from tas_system_topic WHERE project_id = '%v' and `status` = 1 )", project.WorkProjectId))
	}
	topicServe.WhereStr = append(topicServe.WhereStr, fmt.Sprintf("receiver_id = \"\" OR receiver_id IS NULL"))
	topicServe.WhereStr = append(topicServe.WhereStr, fmt.Sprintf("end_date_time > '%s'", time.Now().Format(timehandler.FormatLayoutTime)))
	//topicServe.WhereStr = append(topicServe.WhereStr, fmt.Sprintf("(status = 0 and effective_time < '%s') OR (status = 5)", time.Now().Format(utils.ServerConf.TimeLayoutStr)))
	if lastCount, err := topicServe.Count(); err != nil {
		return err
	} else {
		if lastCount > int64(user.LowerLimit) {
			if user.LowerLimit > topicNumber {
				return errors.New(fmt.Sprintf("最低领取%d题", user.LowerLimit))
			}
		}
	}

	if user.Limit < topicNumber {
		return errors.New(fmt.Sprintf("最多只能领取%d题", user.Limit))
	}
	err = _db.Transaction(func(tx *gorm.DB) error {
		// 查询待领取的题目
		var topicIds []struct {
			Id            uint      `json:"id"`
			TopicId       string    `json:"topic_id"`
			EndDateTime   time.Time `json:"end_date_time"`
			Labels        string    `json:"labels"`
			Title         string    `json:"title"`
			EffectiveTime time.Time `json:"effective_time"`
			FinishTime    time.Time `json:"finish_time"`
		}
		if project.EnumType == modelbase.AuditProj {
			tx.Model(modelbase.SystemTopic{}).
				Where("end_date_time > ?", time.Now().Format(timehandler.FormatLayoutTime)).
				//Where("(status = 0 and effective_time < ?) OR (status = 5)", time.Now().Format(utils.ServerConf.TimeLayoutStr)).
				Where("status = 5").
				Where("project_id = (?)", projectId).
				Where("topic_id in (select topic_id from tas_system_topic WHERE project_id = ? and `status` = 1 )", project.WorkProjectId).
				Where("receiver_id IS NULL OR receiver_id = \"\"").
				Select("id,topic_id,end_date_time,labels,title,effective_time,finish_time").
				Order("priority asc,id asc").
				Find(&topicIds)
		} else if project.EnumType == modelbase.FinalProj {
			dbSelect := tx.Model(modelbase.SystemTopic{})
			dbSelect.Where("end_date_time > ?", time.Now().Format(timehandler.FormatLayoutTime))
			dbSelect.Where("status = 5")
			dbSelect.Where("project_id = (?)", projectId)
			dbSelect.Where("topic_id in (select topic_id from tas_system_topic WHERE project_id = ? and `status` = 1 )", project.WorkProjectId)
			dbSelect.Where("topic_id in (select topic_id from tas_system_topic WHERE project_id = ? and `status` = 1 and audit_status = 1 )", project.AuditProjectId)
			dbSelect.Where("receiver_id IS NULL OR receiver_id = \"\"")
			if utils.StringIsNotEmpty(respondentId) {
				dbSelect.Where("topic_id in (select topic_id from tas_system_topic WHERE project_id = ? and `status` = 1 and receiver_id = ? )", project.WorkProjectId, respondentId)
			}
			if utils.StringIsNotEmpty(teacherId) {
				dbSelect.Where("topic_id in (select topic_id from tas_system_topic WHERE project_id = ? and `status` = 1 and audit_status = 1 and receiver_id = ? )", project.AuditProjectId, teacherId)
			}
			if utils.StringIsNotEmpty(teamNumber) {
				dbSelect.Where("team_number = (?)", teamNumber)
			}
			dbSelect.Select("id,topic_id,end_date_time,labels,title,effective_time,finish_time")
			dbSelect.Order("priority asc,id asc")
			dbSelect.Find(&topicIds)

			/*tx.Model(modelbase.SystemTopic{}).
			Where("end_date_time > ?", time.Now().Format(timehandler.FormatLayoutTime)).
			//Where("(status = 0 and effective_time < ?) OR (status = 5)", time.Now().Format(utils.ServerConf.TimeLayoutStr)).
			Where("status = 5").
			Where("project_id = (?)", projectId).
			Where("topic_id in (select topic_id from tas_system_topic WHERE project_id = ? and `status` = 1 )", project.WorkProjectId).
			Where("topic_id in (select topic_id from tas_system_topic WHERE project_id = ? and `status` = 1 and audit_status = 1 )", project.AuditProjectId).
			Where("receiver_id IS NULL OR receiver_id = \"\"").
			Where("topic_id in (select topic_id from tas_system_topic WHERE project_id = ? and `status` = 1 and receiver_id = ? )", project.WorkProjectId, respondentId).
			Where("topic_id in (select topic_id from tas_system_topic WHERE project_id = ? and `status` = 1 and audit_status = 1 and receiver_id = ? )", project.AuditProjectId, teacherId).
			Where("team_number = (?)", teamNumber).
			Select("id,topic_id,end_date_time,labels,title,effective_time,finish_time").
			Order("priority asc,id asc").
			Find(&topicIds)*/
		} else {
			tx.Model(modelbase.SystemTopic{}).
				Where("end_date_time > ?", time.Now().Format(timehandler.FormatLayoutTime)).
				//Where("(status = 0 and effective_time < ?) OR (status = 5)", time.Now().Format(utils.ServerConf.TimeLayoutStr)).
				Where("status = 5").
				Where("project_id = (?)", projectId).
				Where("receiver_id IS NULL OR receiver_id = \"\"").
				Select("id,topic_id,end_date_time,labels,title,effective_time,finish_time").
				Order("priority asc,id asc").
				Find(&topicIds)
		}

		var userRecords []modelbase.TopicUserRecord
		for _, topic := range topicIds {
			// 领取数量
			if len(userRecords) == topicNumber {
				break
			}
			// 题目ID
			if topicId != "" && topic.TopicId != topicId {
				continue
			}
			// 题目名称
			if topicName != "" && topic.Title != topicName {
				continue
			}
			// 标签
			if labels != "" {
				var contains bool
				for _, label := range strings.Split(labels, ";") {
					if strings.Contains(topic.Labels, label) {
						contains = true
						break
					}
				}
				if !contains {
					continue
				}
			}
			// 题目开始时间
			if tsTime > 0 && topic.EffectiveTime.Unix() < tsTime {
				continue
			}
			if teTime > 0 && topic.EffectiveTime.Unix() > teTime {
				continue
			}

			var ids []uint
			ids = append(ids, topic.Id)
			userRecords = append(userRecords, modelbase.TopicUserRecord{
				SystemTopicId: topic.Id,
				TopicId:       topic.TopicId,
				ProjectId:     projectId,
				UserId:        userId,
				Tp:            1,
				GiveUpReason:  "",
			})
			var finishTime time.Time
			if time.Now().In(utils.LocationZone).Add(time.Second * time.Duration(project.CountdownAnswer)).After(topic.EndDateTime) {
				finishTime = topic.EndDateTime
			} else {
				finishTime = time.Now().Add(time.Second * time.Duration(project.CountdownAnswer))
			}
			if finishTime.In(utils.LocationZone).After(project.OfflineDateTime) {
				finishTime = project.OfflineDateTime
			}
			//修改题目表数据
			if err := tx.Model(&modelbase.SystemTopic{}).Clauses(clause.Returning{}).
				Where("id IN (?)", ids).
				Updates(map[string]interface{}{"receiver_id": userId, "status": 2, "finish_time": finishTime}).Error; err != nil {
				return err
			}

			//创建redis 过期事件
			expiration := finishTime.Unix() - time.Now().In(utils.LocationZone).Unix()
			//key := fmt.Sprintf("task_topic_%d", topicId)
			key := utils.GenerateRedisKey(topic.Id, fmt.Sprintf("2"))
			value, _ := jsoniter.Marshal(map[string]interface{}{"task_type": 2, "status": 5})
			if setNX := redis.RedisGClient.SetNX(key, value, time.Duration(expiration)*time.Second).Err(); setNX != nil {
				return setNX
			}
			/*var topicServer services.TopicService
			if err := topicServer.TopicCountdownAnswer(topic.Id, finishTime); err != nil {
				return err
			}*/
		}
		if len(userRecords) == 0 {
			return errors.New("当前项目没有题目可以领取")
		}
		if err := tx.Model(&modelbase.TopicUserRecord{}).Create(&userRecords).Error; err != nil {
			return err
		}
		return nil
	})
	return
}

/*
 * GiveUpTopic
 * @Description: 放弃单个题目
 * @receiver t
 * @param systemTopicId
 * @param reason
 * @param oss_path
 * @return err
 */

func (t *TopicService) GiveUpTopic(systemTopicId, id uint, reason string, oss_path []string) (err error) {
	_db := mysql.GetDB()
	return _db.Transaction(func(tx *gorm.DB) error {
		var topicServe dao.Common[dao.SystemTopic]
		topic, err := topicServe.First(map[string]interface{}{"id": systemTopicId})
		if err != nil {
			return err
		}
		if topic.ReceiverId == "" {
			return errors.New("当前题目不属于您的题目，请先领取后才可以放弃！")
		}
		var userRestrictionServ dao.Common[dao.SystemUserRestriction]
		userRestrictionServ.Query = map[string]interface{}{"project_id": topic.ProjectId, "system_user_id": id}
		if userRestriction, err := userRestrictionServ.First(userRestrictionServ.Query); err == nil {
			//判断总放弃数量是否超过当日能放弃的上限
			if userRestriction.DayLimit > 0 {
				var topicServ admindao.Common[dao.TopicUserRecord]
				sql := fmt.Sprintf("select count(1) total from tas_topic_user_record where user_id = (select user_id from tas_system_user where id = %v) and left(created_at,10) = DATE_FORMAT(NOW(), '%%Y-%%m-%%d') and tp = 2 and project_id = '%v'", id, topic.ProjectId)
				if amount, err := topicServ.RawCount(sql, "total"); err == nil {
					if amount+1 > int64(userRestriction.DayGiveUpLimit) {
						return errors.New("已达到今日放弃上限，请明日再来")
					}
				}
			}
		}
		//删除之前答题倒计时的任务
		tx.Model(&dao.SystemTask{}).Unscoped().Where(map[string]interface{}{"system_topic_id": systemTopicId, "task_type": 0}).Delete(&dao.SystemTask{})
		//删除redis中的答题倒计时任务
		redis.RedisGClient.Del(fmt.Sprintf("task_topic@%d_%s", systemTopicId, "0"))

		//添加操作记录  topic_user_record tp 值为0
		var recordDao dao.Common[modelbase.TopicUserRecord]
		recordDao.Tx = tx
		var record modelbase.TopicUserRecord
		record.GiveUpReason = reason
		record.TopicId = topic.TopicId
		record.ProjectId = topic.ProjectId
		record.SystemTopicId = systemTopicId
		record.UserId = topic.ReceiverId
		record.Tp = 0
		if err := recordDao.CreateOne(record).Error; err != nil {
			return err
		}

		//删除已经作答的数据
		var answerDao dao.Common[dao.TopicAnswer]
		answerDao.Query = map[string]interface{}{"system_topic_id": topic.Id, "user_id": topic.ReceiverId}
		if err := answerDao.RemoveUnscopedWhere(answerDao.Query).Error; err != nil {
			return err
		}
		//删除oss的文件
		for _, s := range oss_path {
			re := regexp.MustCompile(fmt.Sprintf(`%s/\d{14}`, topic.ProjectId))
			matched := re.FindAllString(s, 1)
			split := strings.Split(matched[0], "/")
			client := oss.BucketClient{}
			timePath := split[1]
			if topic.Status == 4 {
				timePath += "(返修)"
			}
			filename := fmt.Sprintf("task-assign/%s/%s/%s", topic.ProjectId, timePath, topic.TopicId)
			fmt.Println(filename)
			go client.BatchRemoveFiles(filename)
		}
		//修改当前题目的 领取人信息
		if topic.GiveUpNumber >= 1 {
			if topic.GiveUpNumber == 1 {
				topic.GiveUpNumber = topic.GiveUpNumber - 1
				//当题目的被放弃数量达到指定阀值，触发作废操作。将其状态修改为作废状态6
				topic.Status = 6
			} else {
				//自动缩减放弃次数阀值
				topic.GiveUpNumber = topic.GiveUpNumber - 1
				topic.Status = 5
			}
		} else {
			topic.GiveUpNumber = 0
			topic.Status = 6
		}

		topic.ReceiverId = ""
		topic.Priority += 1
		if err := tx.Save(&topic).Error; err != nil {
			return err
		}
		return nil
	})
}

/*
 * 提交答案/审批
 */

func (t *TopicService) SubmitAnswer(topic []dao.TopicAnswer, tp, audit, rejectTime int) error {
	if len(topic) == 0 {
		return nil
	}
	_db := mysql.GetDB()

	return _db.Transaction(func(tx *gorm.DB) error {
		// 每次提交都添加答案记录
		if err := tx.Model(&dao.TopicAnswer{}).Create(&topic).Error; err != nil {
			return err
		}
		//生成txt上传到oss
		client := oss.BucketClient{}
		bucket, _ := oss.NewOss()
		datePath := time.Now().In(utils.LocationZone).Format("20060102150405")
		for _, answer := range topic {
			if answer.Tp == 0 {
				if tp == 2 {
					datePath = datePath + "(返修)"
				}
				if answer.AnswerSize > 0 {
					fileName := fmt.Sprintf("task-assign-project/%s/%s/%s/%d-在线文本.txt", answer.ProjectId, datePath, answer.TopicId, answer.TopicConfigurationId)
					client.UpBytes([]byte(answer.Content), fileName)
				}
			} else {
				if answer.Tp == 1 {
					if utils.StringIsNotEmpty(answer.Content) {
						lastIndex := strings.LastIndex(answer.Content, "/")
						fileUrl := strings.LastIndex(answer.Content, utils.ServerConf.AliOssConf.EndPoint)
						content, _ := url.QueryUnescape(answer.Content[fileUrl+len(utils.ServerConf.AliOssConf.EndPoint)+1:])
						contentLastIndex := strings.LastIndex(content, "/")
						bucket.CopyObject(content, fmt.Sprintf("task-assign-project/%s/%s/%s/%s", answer.ProjectId, datePath, answer.TopicId, content[contentLastIndex+1:]))
						answer.Content = utils.ServerConf.AliOssConf.CallBackHost + fmt.Sprintf("/task-assign-project/%s/%s/%s/%s", answer.ProjectId, datePath, answer.TopicId, answer.Content[lastIndex+1:])
						if err := tx.Model(&dao.TopicAnswer{}).Where("id = ?", answer.Id).Update("content", answer.Content).Error; err != nil {
							return err
						}
					}
				} else if answer.Tp == 2 {
					if utils.StringIsNotEmpty(answer.FileUrl) {
						lastIndex := strings.LastIndex(answer.FileUrl, "/")
						//fileUrl := strings.LastIndex(answer.FileUrl, utils.ServerConf.AliOssConf.Bucket)
						fileUrl := strings.LastIndex(answer.FileUrl, utils.ServerConf.AliOssConf.EndPoint)
						bucket.CopyObject(answer.FileUrl[fileUrl+len(utils.ServerConf.AliOssConf.EndPoint)+1:], fmt.Sprintf("task-assign-project/%s/%s/%s/%s", answer.ProjectId, datePath, answer.TopicId, answer.FileUrl[lastIndex+1:]))
						answer.FileUrl = utils.ServerConf.AliOssConf.CallBackHost + fmt.Sprintf("/task-assign-project/%s/%s/%s/%s", answer.ProjectId, datePath, answer.TopicId, answer.FileUrl[lastIndex+1:])

						updateMap := map[string]interface{}{}
						updateMap["file_url"] = answer.FileUrl

						if answer.AnswerSize > 0 {
							//把富文本变成html文件上传
							fileName := fmt.Sprintf("task-assign-project/%s/%s/%s/%d-在线文本.html", answer.ProjectId, datePath, answer.TopicId, answer.TopicConfigurationId)
							client.UpBytes([]byte(answer.Content), fileName)
							answer.ContentUrl = utils.ServerConf.AliOssConf.CallBackHost + fmt.Sprintf("/task-assign-project/%s/%s/%s/%d-在线文本.html", answer.ProjectId, datePath, answer.TopicId, answer.TopicConfigurationId)
							updateMap["content_url"] = answer.ContentUrl
						}

						if err := tx.Model(&dao.TopicAnswer{}).Where("id = ?", answer.Id).Updates(updateMap).Error; err != nil {
							return err
						}
					} else {
						if answer.AnswerSize > 0 {
							//把富文本变成html文件上传
							fileName := fmt.Sprintf("task-assign-project/%s/%s/%s/%d-在线文本.html", answer.ProjectId, datePath, answer.TopicId, answer.TopicConfigurationId)
							client.UpBytes([]byte(answer.Content), fileName)
							answer.ContentUrl = utils.ServerConf.AliOssConf.CallBackHost + fmt.Sprintf("/task-assign-project/%s/%s/%s/%d-在线文本.html", answer.ProjectId, datePath, answer.TopicId, answer.TopicConfigurationId)
							updateMap := map[string]interface{}{}
							updateMap["content_url"] = answer.ContentUrl
							if err := tx.Model(&dao.TopicAnswer{}).Where("id = ?", answer.Id).Updates(updateMap).Error; err != nil {
								return err
							}
						}
					}
				}
				//if err := tx.Model(dao.SystemProject{}).Where("project_id = ?", projectId).Update("final_project_id", projectObj.ProjectId).Error; err != nil {
			}
		}
		client.BatchRemoveFiles(fmt.Sprintf("%s/%s/%s", utils.ServerConf.AliOssConf.Bucket, topic[0].ProjectId, topic[0].TopicId))

		var topicUserRecord dao.TopicUserRecord
		var systemTopicIds []uint
		for i, answer := range topic {
			systemTopicIds = append(systemTopicIds, answer.SystemTopicId)
			topicUserRecord.UserId = answer.UserId
			topicUserRecord.TopicId = answer.TopicId
			topicUserRecord.SystemTopicId = answer.SystemTopicId
			topicUserRecord.ProjectId = answer.ProjectId
			topicUserRecord.Tp = 2
			if audit > 0 {
				topicUserRecord.ReviewStatus = utils.IntToString(audit)
			}
			if i > 0 {
				break
			}
		}

		//删除任务列表中的相关数据
		if err := tx.Model(&modelbase.SystemTask{}).Unscoped().Where("system_topic_id IN (?)", systemTopicIds).Delete(&modelbase.SystemTask{}).Error; err != nil {
			return err
		}
		// 仅首次作答添加用户答题记录，返修不添加用户记录
		if tp == 1 {
			if err := tx.Model(&dao.TopicUserRecord{}).Create(&topicUserRecord).Error; err != nil {
				return err
			}
		}
		//修改题目状态和完成时间
		fmt.Println("systemTopicIds===>", systemTopicIds)
		if err := tx.Model(&dao.SystemTopic{}).Where("id IN (?) and status != 1", systemTopicIds).Updates(map[string]interface{}{"status": 1, "finish_time": time.Now()}).Error; err != nil {
			return err
		}
		//删除redis中的任务
		for _, id := range systemTopicIds {
			fmt.Println(fmt.Sprintf("task_topic@%d", id))
			code.RemoveRedisKeys(fmt.Sprintf("task_topic@%d", id))
		}

		projectId := topic[0].ProjectId
		topicId := topic[0].TopicId
		// 查询项目类型
		projectDO := &dao.SystemProject{}
		if err := tx.Where("project_id = ?", projectId).Take(projectDO).Error; err != nil {
			glog.Errorf("SubmitAnswer db.Find failed, err: %s", err.Error())
			return err
		}
		// 普通题目
		if projectDO.EnumType == modelbase.WorkProj {
			// 触发一审复审（如果还未一审，则触发无效）
			t.TopicDelayRepair(topicId, projectDO.AuditProjectId, 1)
			return nil
		}
		// 审核状态
		auditStatus := modelbase.NotAudit
		if audit == modelbase.AuditPass {
			// 一审通过
			if projectDO.EnumType == modelbase.AuditProj {
				auditStatus = modelbase.FirstAuditPass
				// 触发二审复审（如果还未二审，则触发无效）
				t.TopicDelayRepair(topicId, projectDO.FinalProjectId, 1)
			}
			// 二审通过
			if projectDO.EnumType == modelbase.FinalProj {
				auditStatus = modelbase.FinalAuditPass
			}
			// 更新答主题目审核状态
			/*if err := tx.Model(&dao.SystemTopic{}).Where("project_id = ? AND topic_id = ?", projectDO.WorkProjectId, topicId).Update("audit_status", auditStatus).Error; err != nil {
				glog.Errorf("SubmitAnswer db.Update failed, err: %s", err.Error())
				return err
			}*/
		}
		// 审核不通过
		if audit == modelbase.AuditNotPassed {
			expiration := 1 // 立刻返修
			nowUnix := int(time.Now().Unix())
			// 定时返修
			if rejectTime > nowUnix {
				expiration = rejectTime - nowUnix
			}
			// 延迟题目返修
			t.TopicDelayRepair(topicId, projectDO.WorkProjectId, expiration)
			// 如果是延迟返修,则更新答主项目返修时间
			if expiration > 1 {
				if err := tx.Model(&dao.SystemTopic{}).Where("project_id = ? AND topic_id = ?", projectDO.WorkProjectId, topicId).Update("reject_time", time.Unix(int64(rejectTime), 0)).Error; err != nil {
					glog.Errorf("SubmitAnswer db.Update failed, err: %s", err.Error())
					return err
				}
			}
		}
		//如果是一审项目,则同时修改答主项目审核状态
		if projectDO.EnumType == modelbase.AuditProj {
			// 更新一审项目审核状态
			if err := tx.Model(&dao.SystemTopic{}).Where("project_id = ? AND topic_id = ?", projectDO.ProjectId, topicId).Update("audit_status", auditStatus).Error; err != nil {
				glog.Errorf("SubmitAnswer db.Update failed, err: %s", err.Error())
				return err
			}
			// 更新答主项目审核状态
			if err := tx.Model(&dao.SystemTopic{}).Where("project_id = ? AND topic_id = ?", projectDO.WorkProjectId, topicId).Update("audit_status", auditStatus).Error; err != nil {
				glog.Errorf("SubmitAnswer db.Update failed, err: %s", err.Error())
				return err
			}
		} else if projectDO.EnumType == modelbase.FinalProj {
			// 更新二审项目审核状态
			if err := tx.Model(&dao.SystemTopic{}).Where("project_id = ? AND topic_id = ?", projectDO.ProjectId, topicId).Update("audit_status", auditStatus).Error; err != nil {
				glog.Errorf("SubmitAnswer db.Update failed, err: %s", err.Error())
				return err
			}
			// 更新一审项目审核状态
			if err := tx.Model(&dao.SystemTopic{}).Where("project_id = ? AND topic_id = ?", projectDO.AuditProjectId, topicId).Update("audit_status", auditStatus).Error; err != nil {
				glog.Errorf("SubmitAnswer db.Update failed, err: %s", err.Error())
				return err
			}
			// 更新答主项目审核状态
			if err := tx.Model(&dao.SystemTopic{}).Where("project_id = ? AND topic_id = ?", projectDO.WorkProjectId, topicId).Update("audit_status", auditStatus).Error; err != nil {
				glog.Errorf("SubmitAnswer db.Update failed, err: %s", err.Error())
				return err
			}
		} else {
			// 更新审核状态
			if err := tx.Model(&dao.SystemTopic{}).Where("project_id = ? AND topic_id = ?", projectDO.ProjectId, topicId).Update("audit_status", auditStatus).Error; err != nil {
				glog.Errorf("SubmitAnswer db.Update failed, err: %s", err.Error())
				return err
			}
		}
		return nil
	})
}

// TopicDelayRepair 延迟题目返修
func (t *TopicService) TopicDelayRepair(topicId, projectId string, expiration int) {
	glog.Infof("TriggerTopicRepair topic_id = %v, project_id = %v, expiration = %v", topicId, projectId, expiration)

	topicDO := &dao.SystemTopic{}
	// 查询题目
	if err := mysql.GetDB().Where("project_id = ? AND topic_id = ?", projectId, topicId).First(topicDO).Error; err != nil {
		glog.Errorf("TriggerTopicRepair db.First failed, err: %s", err.Error())
		return
	}
	// 已完成的题目才能返修/复审
	if topicDO.Status != 1 {
		return
	}
	// 创建 redis 过期事件，异步返修
	key := utils.GenerateRedisKey(topicDO.Id, fmt.Sprintf("3"))
	value, _ := jsoniter.Marshal(map[string]interface{}{"task_type": 3, "status": 4})
	if err := redis.RedisGClient.SetNX(key, value, time.Duration(expiration)*time.Second).Err(); err != nil {
		glog.Errorf("TriggerTopicRepair SetNX err: %v", err)
		return
	}
}

// GetTodayTakeNum 查询今日领取数量
func (t *TopicService) GetTodayTakeNum(projectId, userId string) int {
	_db := mysql.GetDB()
	var count int64
	date := time.Now().Format(time.DateOnly)
	if err := _db.Model(&dao.TopicUserRecord{}).Where("project_id = ? AND user_id = ? AND tp = 1 AND created_at BETWEEN ? AND ?", projectId, userId, date+" 00:00:00", date+" 23:59:59").Count(&count).Error; err != nil {
		glog.Infoln("GetTodayGiveUpNum db.Find failed, err:%s", err.Error())
	}
	return int(count)
}

// GetTodayGiveUpNum 查询今日放弃数量
func (t *TopicService) GetTodayGiveUpNum(projectId, userId string) int {
	_db := mysql.GetDB()
	var count int64
	date := time.Now().Format(time.DateOnly)
	if err := _db.Model(&dao.TopicUserRecord{}).Where("project_id = ? AND user_id = ? AND tp = 0 AND created_at BETWEEN ? AND ?", projectId, userId, date+" 00:00:00", date+" 23:59:59").Count(&count).Error; err != nil {
		glog.Infoln("GetTodayGiveUpNum db.Find failed, err:%s", err.Error())
	}
	return int(count)
}

// GetRemainTopicLabelNum 查询剩余标签题目数量
func (t *TopicService) GetRemainTopicLabelNum(projectId string) map[string]int {
	// k -> label name, v -> topic number
	gmp := make(map[string]int)

	_db := mysql.GetDB()
	topics := make([]*dao.SystemTopic, 0)
	if err := _db.Where(`project_id = ? AND receiver_id = "" OR receiver_id IS NULL AND status = 5`, projectId).Find(&topics).Error; err != nil {
		glog.Infoln("GetAllTopicLabel db.Find failed, err:%s", err.Error())
		return gmp
	}
	for _, topic := range topics {
		tmp := make(map[string]bool)
		for _, label := range topic.Labels {
			// 去重
			if _, ok := tmp[label]; ok {
				continue
			}
			tmp[label] = true
			if v, ok := gmp[label]; ok {
				gmp[label] = v + 1
			} else {
				gmp[label] = 1
			}
		}
	}
	return gmp
}

func (t *TopicService) AddOrRemoveUserTopicLimit(userId, projectId string, addLimit, removeLimit uint) error {
	var projectServe dao.Common[dao.SystemProject]
	if project, err := projectServe.First(map[string]interface{}{"project_id": projectId}); err != nil {
		return err
	} else {
		var userRestrictionServe dao.Common[dao.SystemUserRestriction]
		var userServe dao.Common[dao.SystemUser]
		if user, err := userServe.First(map[string]interface{}{"user_id": userId}); err != nil {
			return err
		} else {
			if ur, err := userRestrictionServe.First(map[string]interface{}{"system_user_id": user.Id, "project_id": project.WorkProjectId}); err != nil {
				return err
			} else {
				//领取/放弃上限增加
				if addLimit > 0 {
					ur.DayLimit = ur.DayLimit + addLimit
					ur.DayGiveUpLimit = ur.DayGiveUpLimit + addLimit

					if err := userRestrictionServe.UpdateOne(ur.Id, map[string]interface{}{"day_limit": ur.DayLimit, "day_give_up_limit": ur.DayGiveUpLimit}).Error; err != nil {
						return err
					} else {
						return nil
					}
				}
				//领取/放弃上限减少
				if removeLimit > 0 {
					if removeLimit >= ur.DayLimit {
						ur.DayLimit = 1
					} else {
						ur.DayLimit = ur.DayLimit - removeLimit
					}

					if removeLimit >= ur.DayGiveUpLimit {
						ur.DayGiveUpLimit = 1
					} else {
						ur.DayGiveUpLimit = ur.DayGiveUpLimit - removeLimit
					}

					if err := userRestrictionServe.UpdateOne(ur.Id, map[string]interface{}{"day_limit": ur.DayLimit, "day_give_up_limit": ur.DayGiveUpLimit}).Error; err != nil {
						return err
					} else {
						return nil
					}
				}
			}
		}
	}
	return nil
}
